/*
 *Copyright (c) 2024 Black Sesame Technologies
 *
 *Licensed under the Apache License, Version 2.0 (the ""License"");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an ""AS IS"" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
*/
#include "../wdt/wdt.h"
#include "can_msg.h"
#include "can_input.h"
#include "can_ipc.h"
#include "can_output.h"
#include "eth2can.h"
#include "hscg_firmware_statistic.h"


/**
 * @brief Reset various devices in the switch subsystem.
 */
static void switch_subsystem_devices_reset(void)
{
    uint32 reg_temp;

    // Protect against register miswriting; only after writing 0xABCD1234 can the registers be written.
    REG32(SW_CRM_ADDR) = 0xABCD1234;
    REG32(SW_SYS_CTRL_ADDR) = 0xABCD1234;

    // The register at 0x217B0000 + 0x28 controls various device resets of the switch subsystem (active low).
    reg_temp = REG32_READ(SW_CRM_ADDR + 0x28);

     /*
     * Set specific bits to 1 to deactivate certain subsystem resets (active low).
     * This will deactivate the following resets:
     * bit0  : switch subsystem r5 core0 reset
     * bit6  : switch subsystem r5 core0/1 NIC bus matrix reset
     * bit7  : switch subsystem r5 core2/3 NIC bus matrix reset
     * bit8  : switch subsystem r5 core4/5 NIC bus matrix reset
     * bit9  : switch subsystem reserved matrix reset
     * bit10 : switch subsystem internal sram0 memory reset
     * bit11 : switch subsystem internal sram1 memory reset
     * bit12 : switch subsystem lsp block reset
     * bit13 : switch subsystem CAN apb bus reset
     * bit14 : switch subsystem SDMA0 configuration reset
     * bit15 : switch subsystem SDMA0 core reset
     * bit16 : switch subsystem DMA reset
     * bit17 : switch subsystem flexray AHB NIC bus matrix reset
     * bit18 : switch subsystem clock monitor reset
     * bit19 : switch subsystem SDMA1 configuration reset
     * bit20 : switch subsystem SDMA1 core reset
     * bit21 : switch subsystem standby sram memory reset
     * bit22 : switch subsystem message box reset
     * bit23 : switch subsystem security acceleration configuration reset
     * bit24 : switch subsystem security acceleration core reset
     * bit25 : switch subsystem flexray0 reset
     * bit26 : switch subsystem flexray1 reset
     * bit27...30 : switch subsystem reserved reset
     * bit31 : switch subsystem PVT reset
     */
    reg_temp |= 0xFFFFFFC1;
    REG32(SW_CRM_ADDR + 0x28) = reg_temp;

    // The protect for the register(0x30001ff0) miswriting, only after write ABCD1234, the register can be write.
    REG32(SOC_PMM_ADDR + 0xff0) = 0xABCD1234;
}
extern void enable_caches(void);
/**
 * @brief Main firmware function initializing and running the CAN and Ethernet interfaces.
 */
void firmware_main(void)
{
    // Reset various devices in the switch subsystem.
    switch_subsystem_devices_reset();

    // Initialize various system components.
    can_msg_init();
    eth2can_init();
    can_output_init();
    init_statistics();
    can_ipc_init();

    // Update statistics with a timestamp.
    STATISTICS_UPDATE(timestamp_startup, util_get_GTC_time64());

    while (1) {

        STATISTICS_UPDATE_CODE_TIMESTAMP(TIMESTAMP_CODE_WDG_KICK_START);
        // Kick the watchdog timer to prevent system reset.
        sw_core0_wdt_kick_dog();

        STATISTICS_UPDATE_CODE_TIMESTAMP(TIMESTAMP_CODE_WDG_KICK_END);
        // Run the main processes for CAN input, IPC, Ethernet to CAN, and CAN output.
        STATISTICS_UPDATE_CODE_TIMESTAMP(TIMESTAMP_CODE_CAN_INPUT_START);
        can_input_run();
        STATISTICS_UPDATE_CODE_TIMESTAMP(TIMESTAMP_CODE_CAN_IPC_START);
        can_ipc_run();
        STATISTICS_UPDATE_CODE_TIMESTAMP(TIMESTAMP_CODE_ETH2CAN_START);
        eth2can_run();
        STATISTICS_UPDATE_CODE_TIMESTAMP(TIMESTAMP_CODE_CAN_OUTPUT_START);
        can_output_run();

        STATISTICS_UPDATE_CODE_TIMESTAMP(TIMESTAMP_CODE_CAN_OUTPUT_END);
        STATISTICS_UPDATE_CODE_LOOP();
        staticstics_run();
    }
}
